﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nage.Algorithms.Solution;
using Nage.Examples.RastriginIsland;
using Nage.Examples.RastriginIsland.Topologies;
using Nage.Algorithms.Population;
using Utils.Logger;

namespace Nage.Algorithms.RastriginIsland
{
    public abstract class IslandGeneticAlgorithm<TSol> : GeneticAlgorithmBase<TSol> where TSol : ISolution
    {        
        #region Events
        /// <summary>
        /// Fired when each generation step has been completed
        /// </summary>
        public event Action<Int32, ITopology<TSol>> StepCompleted;
        #endregion

        #region Public properties
        public Int32 NumberOfIslands { get; set; }
        public ITopology<TSol> Topology { get; set; }
        public IMigrationCondition<TSol> MigrationCondition { get; set; } 
        #endregion

        #region Constructors
        public IslandGeneticAlgorithm()
            : base()
        {
        }

        public IslandGeneticAlgorithm(int numberOfIslands, TopologyType topologyType)
            : base()
        {
            TopologyFactory<TSol> factory = new TopologyFactory<TSol>();
            Topology = factory.Create(topologyType);
            NumberOfIslands = numberOfIslands;
        } 
        #endregion

        #region Solve
        public virtual ITopology<TSol> Solve()
        {
            Initialize();
            CLogger.LogDebug("IslandGeneticAlgorithm -> Solve | Creating population");
            for (int i = 0; i < NumberOfIslands; i++)
            {
                IPopulation<TSol> population = PopulationFactory.CreatePopulation();
                population.SetAllEvaluations(SolutionEvaluator);
                Topology.Add(population);
            }

            int generation = 1;
            while (!StopCondition.IsFulfilled())
            {
                CLogger.LogDebug("IslandGeneticAlgorithm -> Solve | Evolving populations");
                foreach (TopologyNode<TSol> node in Topology)
                {
                    node.Population = Evolution.Evolve(node.Population);
                    node.Population.SetAllEvaluations(SolutionEvaluator);
                }

                if (MigrationCondition.ShouldMigrate(generation, Topology))
                {
                    CLogger.LogDebug("IslandGeneticAlgorithm -> Solve | Populations migrate");
                    Topology.Migrate();
                }

                if (StepCompleted != null)
                {
                    StepCompleted(generation, Topology);
                }

                generation++;
            }

            CLogger.LogDebug("IslandGeneticAlgorithm -> Solve | Done");
            return Topology;
        } 
        #endregion

        #region Initialize

        protected override void Initialize()
        {
            base.Initialize();
            if (Topology == null)
            {
                throw new ArgumentException("Topology");
            }
            if (MigrationCondition == null)
            {
                throw new ArgumentException("MigrationCondition");
            }
        } 
        #endregion
    }
}
